package com.spatio.serving.basic.service.template.core.component.invoker;

import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.spatio.serving.basic.service.template.core.component.invoker.config.InvokeProperties;
import com.spatio.serving.common.lib.common.http.SpatioHttpClient;
import com.spatio.serving.common.lib.common.util.GsonFactory;
import com.spatio.serving.common.lib.common.util.LatencyWatch;
import com.spatio.serving.spring.boot.starter.prometheus.op.impl.HttpInvokePrometheusOp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class IdGenInvoker {

    private static final LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(100000);


    @Resource
    private InvokeProperties invokeProperties;
    @Resource
    private SpatioHttpClient spatioHttpClient;

    public String getIdGenValue() {
        synchronized (this) {
            HttpInvokePrometheusOp.op().qpsTotal("idGenInvoker_getIdGenValue");
            LatencyWatch watch = LatencyWatch.start();
            //Stack<Integer>qq=new Stack<Integer>();

            try {
                String idGen = queue.poll();
                if (null == idGen || queue.size() < 10) {
                    JsonObject requestBody = new JsonObject();
                    requestBody.addProperty("partner", invokeProperties.getIdGen().getPartner());
                    requestBody.addProperty("key", invokeProperties.getIdGen().getKey());
                    JsonObject count = new JsonObject();
                    // count should be n * 99
                    count.addProperty("count", Long.parseLong(invokeProperties.getIdGen().getBatchCount()));
                    requestBody.add("id_snow", count);
                    watch = LatencyWatch.start();
                    String responseStr = spatioHttpClient.postWithBody(invokeProperties.getIdGen().getUrl(), GsonFactory.getDefaultGson().toJson(requestBody), null, 1000);
                    HttpInvokePrometheusOp.op().latency("idGenInvoker_getIdGenValue", watch.cost(), TimeUnit.MILLISECONDS);
                    if (responseStr == null) {
                        log.error("invoke url={}, http result body is null", invokeProperties.getIdGen().getUrl());
                        return null;
                    }
                    JsonObject response = GsonFactory.getDefaultGson().fromJson(responseStr, JsonObject.class);
                    if (0 != response.get("code").getAsInt()) {
                        log.error("idGenInvoker_getIdGenValue  failed:" + response.get("msg"));
                        return null;
                    }
                    List<String> result = GsonFactory.getDefaultGson().fromJson(response.get("result").getAsJsonObject().get("id_snow").getAsJsonArray(), new TypeToken<List<String>>() {
                    }.getType());
                    queue.addAll(result);
                    if (null == idGen) {
                        idGen = queue.poll();
                        log.info(" get idGen =>{} from queue after invoke", idGen);
                    }
                } else {
                    log.info(" get idGen =>{} from queue directly ", idGen);
                }
                HttpInvokePrometheusOp.op().qpsSuccess("idGenInvoker_getIdGenValue");
                return idGen;
            } catch (Exception e) {
                HttpInvokePrometheusOp.op().qpsFail("idGenInvoker_getIdGenValue");
                log.error("idGenInvoker_getIdGenValue exception", e);
            }
            HttpInvokePrometheusOp.op().latency("idGenInvoker_getIdGenValue", watch.totalCost(), TimeUnit.MILLISECONDS);
            return null;
        }
    }

}

